package com.cloudfast.manager.impl;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cloudfast.manager.BaseManager;
import com.cloudfast.utils.OsUtil;

/**
 * 基础实现类
 *
 * @author liuyw
 */
public class BaseManagerImpl implements BaseManager {
    private static final Logger logger = LoggerFactory.getLogger(Logger.class);

    private static final int BUFFER = 8192;

    protected int maxFileSize;

    @Override
    public byte[] fileToByte(String filePath) {
        File file = new File(localStoragePath(filePath));
        byte[] data = null;
        int len;
        byte[] bs = new byte[1024];

        if (file.exists()) {
            try (ByteArrayOutputStream bout = new ByteArrayOutputStream();
                 FileInputStream fs = new FileInputStream(file);) {
                while ((len = fs.read(bs)) != -1) {
                    bout.write(bs, 0, len);
                }
                // 转成byte字节
                data = bout.toByteArray();
            } catch (IOException e) {
                logger.error("File to Byte:{}", e.getMessage());
            }
            file.delete();
        }

        return data;
    }

    @Override
    public String byteToFile(String filePath, byte[] data) {
        OutputStream fos = null;
        try {
            File file = new File(localStoragePath(filePath));
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            fos = new FileOutputStream(file);
            fos.write(data);
            fos.flush();
            return file.getAbsolutePath();
        } catch (Exception e) {
            logger.error("Byte to File:{}", e.getMessage());
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                logger.error("OutputStream Close:{}", e.getMessage());
            }

        }
        return null;
    }

    @Override
    public String localStoragePath(String suffixFileName) {
        StringBuilder path = new StringBuilder();
        if (OsUtil.isWindows()) {
            path.append(OsUtil.getLastWindowsDisk());
        }
        path.append("/FileStorage/");
        File file = new File(path.toString(), "1.txt");
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        if (StringUtils.isNotEmpty(suffixFileName)) {
            suffixFileName = suffixFileName.replaceAll("\\\\", "/");
            suffixFileName = suffixFileName.replaceAll(path.toString(), "");
            path.append(suffixFileName);
        }
        return path.toString().replaceAll("\\\\", "/");
    }

    @Override
    public byte[] compressedFile(String zipName, List<File> files) {
        File zipFile = new File(this.localStoragePath(zipName));
        ZipOutputStream out = null;
        CheckedOutputStream cos = null;
        try (FileOutputStream fileOutputStream = new FileOutputStream(zipFile);) {
            cos = new CheckedOutputStream(fileOutputStream, new CRC32());
            out = new ZipOutputStream(cos);
            String basedir = "";
            for (File file : files) {
                compress(file, out, basedir);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        } finally {
            try {
                if (cos != null) {
                    cos.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                logger.error(e.getMessage());
            }
        }

        return null;
    }

    private void compress(File file, ZipOutputStream out, String basedir) {
        /* 判断是目录还是文件 */
        if (file.isDirectory()) {
            this.compressDirectory(file, out, basedir);
        } else {
            this.compressFile(file, out, basedir);
        }
    }

    /**
     * 压缩一个目录
     */
    private void compressDirectory(File dir, ZipOutputStream out, String basedir) {
        if (!dir.exists())
            return;

        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            /* 递归 */
            compress(files[i], out, basedir + dir.getName() + "/");
        }
    }

    /**
     * 压缩一个文件
     */
    private void compressFile(File file, ZipOutputStream out, String basedir) {
        if (!file.exists()) {
            return;
        }
        BufferedInputStream bis = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(file));
            ZipEntry entry = new ZipEntry(basedir + file.getName());
            out.putNextEntry(entry);
            int count;
            byte data[] = new byte[BUFFER];
            while ((count = bis.read(data, 0, BUFFER)) != -1) {
                out.write(data, 0, count);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        } finally {
            try {
                if (bis != null) {
                    bis.close();
                }
            } catch (Exception e2) {
                logger.error(e2.getMessage());
            }
        }
    }

}
